import type { RouteLocationPathRaw, RouteLocationNamedRaw } from 'vue-router'
import type { Module, ActionContext } from 'vuex'
import type { AxiosResponse } from 'axios'
import type {
  UserStateType,
  UserInfoType,
  PermissionType,
  MenuType,
  ButtonsResponseType
} from './user.typings'
import router from '~/router'
import { cloneDeep } from 'lodash'
import { setToken, removeToken } from '~/utils/auth'
import { setStore, getStore } from '~/utils/store'
import { isURL, validatenull } from '~/utils/validate'
import { deepFindItemByKey, changeDocumentTitle } from '~/utils/util'
import defaultSettings from '~/defaultSettings'
import {
  loginByUsername,
  // refreshUserLogin,
  getUserInfo,
  // refreshToken,
  // logout,
  getTopMenu,
  getMenu,
  getButtons,
  getCaptcha,
  getCurrentTenant,
  getUserUpdatePassword
} from '~/api/user'

function addPath(ele: Record<string, any>, first?: boolean | undefined) {
  const {
    menu: {
      iconDefault,
      props: { key, label, path, icon, children }
    }
  } = defaultSettings

  const propsDefault = {
    key: key || 'code',
    label: label || 'name',
    path: path || 'path',
    icon: icon || 'icon',
    children: children || 'children'
  }
  const eleIcon = ele[propsDefault.icon]
  ele[propsDefault.icon] = validatenull(eleIcon) ? iconDefault : eleIcon
  const isChild = ele[propsDefault.children] && ele[propsDefault.children].length !== 0
  if (!isChild) ele[propsDefault.children] = []
  if (!isChild && first && !isURL(ele[propsDefault.path])) {
    ele[propsDefault.path] = `${ele[propsDefault.path]}/index`
  } else {
    ele[propsDefault.children].forEach((child: any) => {
      addPath(child)
    })
  }
}

const user: Module<UserStateType, UserStateType> = {
  namespaced: true,
  state: {
    userInfo: getStore({ name: 'userInfo' }) as UserInfoType,
    permission: new Set(),
    roles: [],
    menu: [],
    menuAll: [],
    token: getStore({ name: 'token' }) as string,
    language: (getStore({ name: 'language' }) ||
      defaultSettings.language) as UserStateType['language'],
    userAddressInfo: {}
  },
  getters: {
    userInfo: (state) => state.userInfo,
    permission: (state) => state.permission,
    token: (state) => state.token,
    language: (state) => state.language,
    userAddressInfo: (state) => state.userAddressInfo
  },
  mutations: {
    SET_TOKEN: (
      state: UserStateType,
      payload: { token: UserStateType['token'] } = {
        token: ''
      }
    ) => {
      const { token } = payload
      removeToken()
      setToken(token)
      state.token = token
      setStore({ name: 'token', content: token, type: 'session' })
    },
    SET_USER_INFO: (state: UserStateType, userInfo: UserStateType['userInfo']) => {
      state.userInfo = userInfo
      setStore({ name: 'userInfo', content: state.userInfo })
    },
    SET_MENU_ALL: (state: UserStateType, menuAll: UserStateType['menuAll']) => {
      state.menuAll = menuAll
      // setStore({ name: 'menuAll', content: state.menuAll, type: 'session' })
    },
    SET_MENU: (state: UserStateType, menu: UserStateType['menu']) => {
      state.menu = menu
      // setStore({ name: 'menu', content: state.menu, type: 'session' })
      if (validatenull(menu)) return
      // 合并动态路由去重
      let menuAll = state.menuAll
      menuAll = menuAll.concat(menu).reverse()
      const newMenu: MenuType[] = []
      for (const item1 of menuAll) {
        let flag = true
        for (const item2 of newMenu) {
          if (item1.name === item2.name || item1.path === item2.path) {
            flag = false
          }
        }
        if (flag) newMenu.push(item1)
      }
      state.menuAll = newMenu
      // setStore({ name: 'menuAll', content: state.menuAll, type: 'session' })
    },
    SET_ROLES: (state: UserStateType, roles: UserStateType['roles']) => {
      state.roles = roles
    },
    SET_PERMISSION: (state: UserStateType, permission: ButtonsResponseType[]) => {
      state.permission = new Set()
      const result: (keyof PermissionType)[] = []
      function getCode(list: ButtonsResponseType[]) {
        list.forEach((ele) => {
          if (typeof ele === 'object') {
            const chiildren = ele.children
            const code = ele.code
            if (chiildren) {
              getCode(chiildren)
            } else {
              result.push(code)
            }
          }
        })
      }
      getCode(permission)
      result.forEach((ele: keyof PermissionType) => {
        // state.permission[ele] = true
        state.permission.add(ele)
      })
      // setStore({ name: 'permission', content: state.permission, type: 'session' })
    },
    SET_USERADDRESSINFO: (
      state: UserStateType,
      userAddressInfo: UserStateType['userAddressInfo']
    ) => {
      state.userAddressInfo = userAddressInfo
    }
  },
  actions: {
    // 根据用户名登录
    async LoginByUsername<S, T extends { key?: string | undefined; code?: string | undefined }>(
      { commit }: ActionContext<S, T>,
      userInfo: T
    ) {
      return await loginByUsername<T>(userInfo).then((res: AxiosResponse) => {
        const data = res?.data?.data
        commit('SET_TOKEN', {
          token: data?.accessToken
        })
        commit('SET_USER_INFO', data)
        return res?.data?.data
        // commit('tags/DEL_ALL_TAG')
        // commit('CLEAR_LOCK')
      })
    },
    // 根据手机号登录
    LoginByPhone<S, T extends { key?: string | undefined; code?: string | undefined }>(
      { commit }: ActionContext<S, T>,
      userInfo: T
    ) {
      return new Promise<void>((resolve) => {
        loginByUsername(userInfo).then((res: AxiosResponse) => {
          const data = res.data.data
          commit('SET_TOKEN', {
            token: data?.accessToken
          })
          // commit('DEL_ALL_TAG')
          // commit('CLEAR_LOCK')
          resolve(data)
        })
      })
    },
    // 刷新token
    // RefreshToken<S, T>({ commit, dispatch }: ActionContext<S, T>) {
    //   return new Promise((resolve, reject) => {
    //     const params = {
    //       grantType: 'refresh_token',
    //       refreshToken: getStore({ name: 'refreshToken' })
    //     }
    //     refreshUserLogin(params)
    //       .then(async (res: AxiosResponse) => {
    //         if (res.data.code !== 200) {
    //           await reject(res)
    //           dispatch('FedLogOut').then(() => reject(res))
    //           return
    //         }
    //         const data = res.data.data
    //         commit('SET_TOKEN', {
    //           token: data?.accessToken,
    //           refreshToken: data?.refreshToken
    //         })
    //         await resolve(data)
    //       })
    //       .catch(async (err: AxiosResponse) => {
    //         await reject(err)
    //         dispatch('FedLogOut')
    //       })
    //   })
    // },
    // 获取用户信息
    GetUserInfo<S, T>({ commit }: ActionContext<S, T>) {
      return new Promise((resolve, reject) => {
        getUserInfo()
          .then((res: AxiosResponse) => {
            const data = res.data.data
            commit('SET_ROLES', data.roles)
            resolve(data)
          })
          .catch((err: AxiosResponse) => {
            reject(err)
          })
      })
    },
    // 注销session
    FedLogOut<S, T>({ commit }: ActionContext<S, T>) {
      return new Promise<void>((resolve) => {
        commit('SET_TOKEN', {
          token: ''
        })
        commit('SET_MENU', [])
        commit('SET_MENU_ALL', [])
        commit('SET_ROLES', [])

        commit('tags/DEL_ALL_TAG', null, { root: true })

        // commit('CLEAR_LOCK')
        removeToken()
        changeDocumentTitle()
        router.replace(defaultSettings.loginUrl)
        resolve()
      })
    },
    // 获取顶部菜单
    GetTopMenu() {
      return new Promise((resolve) => {
        getTopMenu().then((res: AxiosResponse) => {
          const data = res.data.data || []
          resolve(data)
        })
      })
    },
    // 获取系统菜单
    GetMenu<S, T>({ commit, dispatch }: ActionContext<S, T>) {
      return new Promise<UserStateType['menu']>((resolve) => {
        getMenu().then((res: AxiosResponse) => {
          const date = res?.data?.data
          const menu = cloneDeep(date?.length ? date : [])
          menu.forEach((ele: Record<string, any>) => addPath(ele, true))
          commit('SET_MENU', menu)
          commit('SET_MENU_ALL', menu)
          dispatch('GetButtons')
          resolve(menu)
        })
      })
    },
    // 获取按钮
    GetButtons<S, T>({ commit }: ActionContext<S, T>) {
      return new Promise((resolve) => {
        getButtons().then((res: AxiosResponse) => {
          const data = res.data.data
          commit('SET_PERMISSION', data)
          resolve(data)
        })
      })
    },
    // 获取验证码
    GetCaptcha() {
      return new Promise((resolve) => {
        getCaptcha().then((res: AxiosResponse) => {
          const data = res.data.data
          resolve(data)
        })
      })
    },
    // 修改密码
    GetUserUpdatePassword<S, T>(_: ActionContext<S, T>, params: T) {
      return new Promise((resolve, reject) => {
        getUserUpdatePassword<T>(params)
          .then((res: AxiosResponse) => {
            resolve(res.data)
          })
          .catch((err: AxiosResponse) => {
            reject(err)
          })
      })
    },
    // 获取租户坐标
    GetCurrentTenant<S, T>({ commit }: ActionContext<S, T>) {
      return new Promise((resolve) => {
        getCurrentTenant().then((res: AxiosResponse) => {
          const data = res.data
          commit('SET_USERADDRESSINFO', res?.data?.data || {})
          resolve(data)
        })
      })
    },
    // 根据路由的path匹配跳转地址
    async MatchRouterPathJumpAddress({ state, commit }, routerPath) {
      const {
        menu: {
          props: { key, label, path, children }
        }
      } = defaultSettings
      const findMenuItem = deepFindItemByKey<MenuType>(state?.menu, path, children, routerPath)
      const flag = findMenuItem && router.hasRoute(findMenuItem[key] as string)
      const tagParams = {
        label: flag ? (findMenuItem![label] as string) : '404',
        value: flag ? (findMenuItem![path] as string) : '/404',
        params: {},
        query: '',
        close: true
      }
      changeDocumentTitle(tagParams.label)
      router.push(tagParams.value)
      commit('tags/ADD_TAG', tagParams, { root: true })
      commit('tags/CHANGE_TAG', tagParams, { root: true })
      return tagParams.value
    },
    // 根据路由的name匹配跳转地址
    async MatchRouterNameJumpAddress({ state, commit }, routerName) {
      const {
        menu: {
          props: { key, label, path, children }
        }
      } = defaultSettings
      const findMenuItem = deepFindItemByKey<MenuType>(state?.menu, key, children, routerName)
      const flag = findMenuItem && router.hasRoute(findMenuItem[key] as string)
      const tagParams = {
        label: flag ? (findMenuItem![label] as string) : '404',
        value: flag ? (findMenuItem![path] as string) : '/404',
        params: {},
        query: '',
        close: true
      }
      changeDocumentTitle(tagParams.label)
      router.push(tagParams.value)
      commit('tags/ADD_TAG', tagParams, { root: true })
      commit('tags/CHANGE_TAG', tagParams, { root: true })
      return tagParams.value
    },
    // 根据路由的name匹配跳转地址
    async MatchRouterOptionsJumpAddress(
      { state, commit },
      option: RouteLocationPathRaw | RouteLocationNamedRaw
    ) {
      const {
        menu: {
          props: { key, label, path, children }
        }
      } = defaultSettings
      const findMenuItem = (option as RouteLocationPathRaw).path
        ? deepFindItemByKey<MenuType>(
            state?.menu,
            path,
            children,
            (option as RouteLocationPathRaw).path
          )
        : deepFindItemByKey<MenuType>(
            state?.menu,
            key,
            children,
            (option as RouteLocationNamedRaw).name as string
          )
      const flag = findMenuItem && router.hasRoute(findMenuItem[key] as string)
      const tagParams = {
        label: flag ? (findMenuItem![label] as string) : '404',
        value: flag ? (findMenuItem![path] as string) : '/404',
        params: {},
        query: '',
        close: true
      }
      changeDocumentTitle(tagParams.label)
      const jumpParams = { ...option, name: undefined, path: undefined }
      delete jumpParams.name
      router.push(Object.assign(jumpParams, { path: tagParams.value }))
      commit('tags/ADD_TAG', tagParams, { root: true })
      commit('tags/CHANGE_TAG', tagParams, { root: true })
      return tagParams.value
    }
  }
}

export default user
